﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using System.Runtime.InteropServices;

namespace FocalSpec.GuiExample.Model
{

    public static class Utils
    {
        [DllImport("kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetPhysicallyInstalledSystemMemory(out long totalMemoryInKilobytes);
    }

    /// <summary>
    /// Stores application settings that can be changed at run-time. Singleton instance.
    /// </summary>
    public sealed class ApplicationSettings
    {
        /// <summary>
        /// Gets or sets the LED pulse width in µs.
        /// </summary>
        public int LedPulseWidth { get; set; }

        /// <summary>
        /// Gets or sets the max. LED pulse width in µs. This is used only if the HW supports Automatic Gain Control (AGC).
        /// </summary>
        public int MaxLedPulseWidth { get; set; }

        /// <summary>
        /// Gets or sets the frequency in Hz.
        /// </summary>
        public int Freq { get; set; }

        /// <summary>
        /// Gets or sets the flag indicating whether external pulsing is enabled or not.
        /// </summary>
        public bool IsExternalPulsingEnabled { get; set; }

        /// <summary>
        /// Gets or sets the IPv4 address of the sensor. If null, auto-ip shall be used.
        /// </summary>
        public string IpAddress { get; set; }

        /// <summary>
        /// Backing-field of <code>ZCalibrationFile</code>.
        /// </summary>
        private string _zCalibrationFile;

        /// <summary>
        /// Gets or sets the Z calibration file.
        /// </summary>
        public string ZCalibrationFile
        {
            get { return _zCalibrationFile; }
            set
            {
                if (value != null)
                {
                    double min, max, avgGain;

                    // Due to nature of the optics, we need to calculate average pixel width [mm].
                    GetCalibrationProperties(value, 0, Defines.DefaultSensorWidth - 1, out min, out max, out avgGain);
                    // if gain was not set calibration file was not found from expected location.
                    if (Math.Abs(avgGain) < double.Epsilon)
                        return;

                    AveragePixelHeight = avgGain;
                }

                _zCalibrationFile = value;
            }
        }

        /// <summary>
        /// Backing-field of <code>XCalibrationFile</code>.
        /// </summary>
        private string _xCalibrationFile;

        /// <summary>
        /// Gets or sets the X calibration file.
        /// </summary>
        public string XCalibrationFile
        {
            get { return _xCalibrationFile; }
            set
            {
                if (value != null)
                {
                    double min, max, avgGain;

                    // Due to nature of the optics, we need to calculate actual min. X [mm], max. X [mm] and average pixel width [mm] from the calibration data of the sensor at hand.
                    GetCalibrationProperties(value, 0, Defines.DefaultSensorWidth - 1, out min, out max, out avgGain);
                    // if gain was not set calibration file was not found from expected loaction.
                    if (Math.Abs(avgGain) < double.Epsilon)
                        return;

                    OpticalProfileMinX = min;
                    OpticalProfileMaxX = max;
                    AveragePixelWidth = avgGain;
                }

                _xCalibrationFile = value;
            }
        }

        /// <summary>
        /// Gets or sets the size of the window in [mm].
        /// </summary>
        public int UiWindowHeight { get; set; }

        /// <summary>
        /// Gets the average pixel width in [mm].
        /// </summary>
        /// <remarks>
        /// Due to the nature of the optics, pixel width is not constant in LCI1600. In LCI400 and LCI1200, it is.
        /// </remarks>
        public double AveragePixelWidth { get; set; }

        /// <summary>
        /// Gets the average pixel height [mm].
        /// </summary>
        public double AveragePixelHeight { get; private set; }

        /// <summary>
        /// Gets or sets the flag indicating whether AGC is enabled or disabled. For systems not supporting AGC, this is always false.
        /// </summary>
        public bool IsAgcEnabled { get; set; }

        /// <summary>
        /// Gets or sets the AGC target intensity.
        /// </summary>
        public float AgcTargetIntensity { get; set; }

        /// <summary>
        /// Gets or sets the PulseDivider for external triggering.
        /// </summary>
        public int PulseDivider { get; set; }

        public double Current { get; set; }
        public double Gain { get; set; }
        public double GainHs { get; set; }

        /// <summary>
        /// Gets or sets the TriggerSource 1...4.
        /// </summary>
        public int TriggerSource { get; set; }

        /// <summary>
        /// Gets or sets the flag indicating whether Image Height is adjusted around the Z-calibarated Zero Position.
        /// </summary>
        public bool HeightZeroAdjustEnabled { get; set; }

        /// <summary>
        /// Gets or sets the pointcloud ASC file additional attributes.
        /// 0: x, y, z coordinates
        /// 1: coordinates + intensity in float format.
        /// 2: coordinates + grayscale value in RGB format. 
        /// 3: coordinates, + intensity + grayscale. 
        /// </summary>
        public int PointCloudAscFormat { get; set; }

        /// <summary>
        /// Gets or sets the FIR length for camera.
        /// </summary>
        public int FirLength { get; set; }

        /// <summary>
        /// Gets or sets the Average FIR length for camera.
        /// </summary>
        public int AverFirLength { get; set; }

        /// <summary>
        /// Gets or sets the detection filter length for camera.
        /// </summary>
        public int DetectionFilter { get; set; }

        /// <summary>
        /// Gets or sets the average intensity length for camera.
        /// </summary>
        public int AverageIntensityFilter { get; set; }

        /// <summary>
        /// Gets or sets the intensity threshold for camera.
        /// </summary>
        public int Threshold { get; set; }

	    /// <summary>
	    /// Gets or sets the maximum point count per profile for camera.
	    /// </summary>
	    public int MaxPointCount { get; set; }

        /// <summary>
        /// Gets or sets the hdr.
        /// </summary>
        public bool HdrEnabled { get; set; }

        /// <summary>
        /// Gets or sets the VLow2.
        /// </summary>
        public int VLow2 { get; set; } = 114;

        /// <summary>
        /// Gets or sets the VLow3.
        /// </summary>
        public int VLow3 { get; set; } = 116;

        /// <summary>
        /// Gets or sets the Kp1Pos.
        /// </summary>
        public int Kp1Pos { get; set; } = 10;

        /// <summary>
        /// Gets or sets the Kp2Pos.
        /// </summary>
        public int Kp2Pos { get; set; } = 25;

        public int ExpectedCameraCount { get; set; }

        private string _cameraIdString;
        private Dictionary<string, string> _cameraIds = new Dictionary<string, string>();

        /// <summary>
        /// Gets or sets the camera id string containing MAC and logical names.
        /// </summary>
        public string CameraIdString
        {
            get { return _cameraIdString; }
            set { _cameraIdString = value; }
        }

        /// <summary>
        /// Gets or sets the save rate used in ASC file saving. 
        /// </summary>
        [JsonIgnore]
        public int SaveRate { get; set; }

        /// <summary>
        /// Gets or sets the camera id string format.
        /// </summary>
        [JsonIgnore]
        public Dictionary<string, string> CameraIds
        {
            get
            {
                _cameraIds.Clear();
                if (string.IsNullOrEmpty(_cameraIdString))
                    return _cameraIds;

                string[] items = _cameraIdString.TrimEnd(';').Split(';');
                foreach (string item in items)
                {
                    string[] keyValue = item.Split('=');
                    _cameraIds.Add(keyValue[0], keyValue[1]);
                }
                return _cameraIds; 
            }
            set
            {
                _cameraIds = value;
                _cameraIdString = string.Join(";", _cameraIds.Select(x => x.Key + "=" + x.Value));
            }
        }

        /// <summary>
        /// Sensor width
        /// </summary>
        [JsonIgnore]
	    public int SensorWidth { get; set; }

	    /// <summary>
	    /// Sensor x offset in pixels
	    /// </summary>
	    [JsonIgnore]
	    public int XOffset { get; set; }

	    /// <summary>
	    /// Sensor type identifier offset in pixels
	    /// </summary>
	    [JsonIgnore]
	    public int SensorType { get; set; }

		/// <summary>
		/// Gets the flag indicating whether the Z calibration data is set or not.
		/// </summary>
		[JsonIgnore]
        public bool IsZCalibrationDataSet
        {
            get { return !string.IsNullOrEmpty(ZCalibrationFile); }
        }

        /// <summary>
        /// Gets the flag indicating whether the X calibration data is set or not.
        /// </summary>
        [JsonIgnore]
        public bool IsXCalibrationDataSet
        {
            get { return !string.IsNullOrEmpty(XCalibrationFile); }
        }

        /// <summary>
        /// Gets the min. x of the optical profile in [mm].
        /// </summary>
        [JsonIgnore]
        public double OpticalProfileMinX { get; set; }

        /// <summary>
        /// Gets the min. x of the optical profile in [mm].
        /// </summary>
        [JsonIgnore]
        public double OpticalProfileMaxX { get; set; }

        //---------------------------------------------------------------------------------------------------
        public int LedPulseWidth2 { get; set; }

        /// <summary>
        /// Gets or sets the max. LED pulse width in µs. This is used only if the HW supports Automatic Gain Control (AGC).
        /// </summary>
        public int MaxLedPulseWidth2 { get; set; }

        /// <summary>
        /// Gets or sets the frequency in Hz.
        /// </summary>
        public int Freq2 { get; set; }

        /// <summary>
        /// Gets or sets the flag indicating whether external pulsing is enabled or not.
        /// </summary>
        public bool IsExternalPulsingEnabled2 { get; set; }

        /// <summary>
        /// Gets or sets the IPv4 address of the sensor. If null, auto-ip shall be used.
        /// </summary>
        public string IpAddress2 { get; set; }

        /// <summary>
        /// Backing-field of <code>ZCalibrationFile</code>.
        /// </summary>
        private string _zCalibrationFile2;

        /// <summary>
        /// Gets or sets the Z calibration file.
        /// </summary>
        public string ZCalibrationFile2
        {
            get { return _zCalibrationFile2; }
            set
            {
                if (value != null)
                {
                    double min, max, avgGain;

                    // Due to nature of the optics, we need to calculate average pixel width [mm].
                    GetCalibrationProperties(value, 0, Defines.DefaultSensorWidth - 1, out min, out max, out avgGain);
                    // if gain was not set calibration file was not found from expected location.
                    if (Math.Abs(avgGain) < double.Epsilon)
                        return;

                    AveragePixelHeight2 = avgGain;
                }

                _zCalibrationFile2 = value;
            }
        }

        /// <summary>
        /// Backing-field of <code>XCalibrationFile</code>.
        /// </summary>
        private string _xCalibrationFile2;

        /// <summary>
        /// Gets or sets the X calibration file.
        /// </summary>
        public string XCalibrationFile2
        {
            get { return _xCalibrationFile2; }
            set
            {
                if (value != null)
                {
                    double min, max, avgGain;

                    // Due to nature of the optics, we need to calculate actual min. X [mm], max. X [mm] and average pixel width [mm] from the calibration data of the sensor at hand.
                    GetCalibrationProperties(value, 0, Defines.DefaultSensorWidth - 1, out min, out max, out avgGain);
                    // if gain was not set calibration file was not found from expected loaction.
                    if (Math.Abs(avgGain) < double.Epsilon)
                        return;

                    OpticalProfileMinX2 = min;
                    OpticalProfileMaxX2 = max;
                    AveragePixelWidth2 = avgGain;
                }

                _xCalibrationFile2 = value;
            }
        }

        /// <summary>
        /// Gets or sets the size of the window in [mm].
        /// </summary>
        public int UiWindowHeight2 { get; set; }

        /// <summary>
        /// Gets the average pixel width in [mm].
        /// </summary>
        /// <remarks>
        /// Due to the nature of the optics, pixel width is not constant in LCI1600. In LCI400 and LCI1200, it is.
        /// </remarks>
        public double AveragePixelWidth2 { get; set; }

        /// <summary>
        /// Gets the average pixel height [mm].
        /// </summary>
        public double AveragePixelHeight2 { get; private set; }

        /// <summary>
        /// Gets or sets the flag indicating whether AGC is enabled or disabled. For systems not supporting AGC, this is always false.
        /// </summary>
        public bool IsAgcEnabled2 { get; set; }

        /// <summary>
        /// Gets or sets the AGC target intensity.
        /// </summary>
        public float AgcTargetIntensity2 { get; set; }

        /// <summary>
        /// Gets or sets the PulseDivider for external triggering.
        /// </summary>
        public int PulseDivider2 { get; set; }

        public double Current2 { get; set; }
        public double Gain2 { get; set; }
        public double GainHs2 { get; set; }

        /// <summary>
        /// Gets or sets the TriggerSource 1...4.
        /// </summary>
        public int TriggerSource2 { get; set; }

        /// <summary>
        /// Gets or sets the flag indicating whether Image Height is adjusted around the Z-calibarated Zero Position.
        /// </summary>
        public bool HeightZeroAdjustEnabled2 { get; set; }

        /// <summary>
        /// Gets or sets the pointcloud ASC file additional attributes.
        /// 0: x, y, z coordinates
        /// 1: coordinates + intensity in float format.
        /// 2: coordinates + grayscale value in RGB format. 
        /// 3: coordinates, + intensity + grayscale. 
        /// </summary>
        public int PointCloudAscFormat2 { get; set; }

        /// <summary>
        /// Gets or sets the FIR length for camera.
        /// </summary>
        public int FirLength2 { get; set; }

        /// <summary>
        /// Gets or sets the Average FIR length for camera.
        /// </summary>
        public int AverFirLength2 { get; set; }

        /// <summary>
        /// Gets or sets the detection filter length for camera.
        /// </summary>
        public int DetectionFilter2 { get; set; }

        /// <summary>
        /// Gets or sets the average intensity length for camera.
        /// </summary>
        public int AverageIntensityFilter2 { get; set; }

        /// <summary>
        /// Gets or sets the intensity threshold for camera.
        /// </summary>
        public int Threshold2 { get; set; }

        /// <summary>
        /// Gets or sets the maximum point count per profile for camera.
        /// </summary>
        public int MaxPointCount2 { get; set; }

        /// <summary>
        /// Gets or sets the hdr.
        /// </summary>
        public bool HdrEnabled2 { get; set; }

        /// <summary>
        /// Gets or sets the VLow2.
        /// </summary>
        public int VLow22 { get; set; } = 114;

        /// <summary>
        /// Gets or sets the VLow3.
        /// </summary>
        public int VLow32 { get; set; } = 116;

        /// <summary>
        /// Gets or sets the Kp1Pos.
        /// </summary>
        public int Kp1Pos2 { get; set; } = 10;

        /// <summary>
        /// Gets or sets the Kp2Pos.
        /// </summary>
        public int Kp2Pos2 { get; set; } = 25;

        public int ExpectedCameraCount2 { get; set; }

        private string _cameraIdString2;
        private Dictionary<string, string> _cameraIds2 = new Dictionary<string, string>();

        /// <summary>
        /// Gets or sets the camera id string containing MAC and logical names.
        /// </summary>
        public string CameraIdString2
        {
            get { return _cameraIdString; }
            set { _cameraIdString = value; }
        }

        /// <summary>
        /// Gets or sets the save rate used in ASC file saving. 
        /// </summary>
        [JsonIgnore]
        public int SaveRate2 { get; set; }

        /// <summary>
        /// Gets or sets the camera id string format.
        /// </summary>
        [JsonIgnore]
        public Dictionary<string, string> CameraIds2
        {
            get
            {
                _cameraIds.Clear();
                if (string.IsNullOrEmpty(_cameraIdString))
                    return _cameraIds;

                string[] items = _cameraIdString.TrimEnd(';').Split(';');
                foreach (string item in items)
                {
                    string[] keyValue = item.Split('=');
                    _cameraIds.Add(keyValue[0], keyValue[1]);
                }
                return _cameraIds;
            }
            set
            {
                _cameraIds = value;
                _cameraIdString = string.Join(";", _cameraIds.Select(x => x.Key + "=" + x.Value));
            }
        }

        /// <summary>
        /// Sensor width
        /// </summary>
        [JsonIgnore]
        public int SensorWidth2 { get; set; }

        /// <summary>
        /// Sensor x offset in pixels
        /// </summary>
        [JsonIgnore]
        public int XOffset2 { get; set; }

        /// <summary>
        /// Sensor type identifier offset in pixels
        /// </summary>
        [JsonIgnore]
        public int SensorType2 { get; set; }

        /// <summary>
        /// Gets the flag indicating whether the Z calibration data is set or not.
        /// </summary>
        [JsonIgnore]
        public bool IsZCalibrationDataSet2
        {
            get { return !string.IsNullOrEmpty(ZCalibrationFile); }
        }

        /// <summary>
        /// Gets the flag indicating whether the X calibration data is set or not.
        /// </summary>
        [JsonIgnore]
        public bool IsXCalibrationDataSet2
        {
            get { return !string.IsNullOrEmpty(XCalibrationFile); }
        }

        /// <summary>
        /// Gets the min. x of the optical profile in [mm].
        /// </summary>
        [JsonIgnore]
        public double OpticalProfileMinX2 { get; set; }

        /// <summary>
        /// Gets the min. x of the optical profile in [mm].
        /// </summary>
        [JsonIgnore]
        public double OpticalProfileMaxX2 { get; set; }


        //-----------------------------------------------------------------------

        //---------------------------------------------------------------------------------------------------
        public int LedPulseWidth3 { get; set; }

        /// <summary>
        /// Gets or sets the max. LED pulse width in µs. This is used only if the HW supports Automatic Gain Control (AGC).
        /// </summary>
        public int MaxLedPulseWidth3 { get; set; }

        /// <summary>
        /// Gets or sets the frequency in Hz.
        /// </summary>
        public int Freq3 { get; set; }

        /// <summary>
        /// Gets or sets the flag indicating whether external pulsing is enabled or not.
        /// </summary>
        public bool IsExternalPulsingEnabled3 { get; set; }

        /// <summary>
        /// Gets or sets the IPv4 address of the sensor. If null, auto-ip shall be used.
        /// </summary>
        public string IpAddress3 { get; set; }

        /// <summary>
        /// Backing-field of <code>ZCalibrationFile</code>.
        /// </summary>
        private string _zCalibrationFile3;

        /// <summary>
        /// Gets or sets the Z calibration file.
        /// </summary>
        public string ZCalibrationFile3
        {
            get { return _zCalibrationFile3; }
            set
            {
                if (value != null)
                {
                    double min, max, avgGain;

                    // Due to nature of the optics, we need to calculate average pixel width [mm].
                    GetCalibrationProperties(value, 0, Defines.DefaultSensorWidth - 1, out min, out max, out avgGain);
                    // if gain was not set calibration file was not found from expected location.
                    if (Math.Abs(avgGain) < double.Epsilon)
                        return;

                    AveragePixelHeight3 = avgGain;
                }

                _zCalibrationFile3 = value;
            }
        }

        /// <summary>
        /// Backing-field of <code>XCalibrationFile</code>.
        /// </summary>
        private string _xCalibrationFile3;

        /// <summary>
        /// Gets or sets the X calibration file.
        /// </summary>
        public string XCalibrationFile3
        {
            get { return _xCalibrationFile3; }
            set
            {
                if (value != null)
                {
                    double min, max, avgGain;

                    // Due to nature of the optics, we need to calculate actual min. X [mm], max. X [mm] and average pixel width [mm] from the calibration data of the sensor at hand.
                    GetCalibrationProperties(value, 0, Defines.DefaultSensorWidth - 1, out min, out max, out avgGain);
                    // if gain was not set calibration file was not found from expected loaction.
                    if (Math.Abs(avgGain) < double.Epsilon)
                        return;

                    OpticalProfileMinX3 = min;
                    OpticalProfileMaxX3 = max;
                    AveragePixelWidth3 = avgGain;
                }

                _xCalibrationFile3 = value;
            }
        }

        /// <summary>
        /// Gets or sets the size of the window in [mm].
        /// </summary>
        public int UiWindowHeight3 { get; set; }

        /// <summary>
        /// Gets the average pixel width in [mm].
        /// </summary>
        /// <remarks>
        /// Due to the nature of the optics, pixel width is not constant in LCI1600. In LCI400 and LCI1200, it is.
        /// </remarks>
        public double AveragePixelWidth3 { get; set; }

        /// <summary>
        /// Gets the average pixel height [mm].
        /// </summary>
        public double AveragePixelHeight3 { get; private set; }

        /// <summary>
        /// Gets or sets the flag indicating whether AGC is enabled or disabled. For systems not supporting AGC, this is always false.
        /// </summary>
        public bool IsAgcEnabled3 { get; set; }

        /// <summary>
        /// Gets or sets the AGC target intensity.
        /// </summary>
        public float AgcTargetIntensity3 { get; set; }

        /// <summary>
        /// Gets or sets the PulseDivider for external triggering.
        /// </summary>
        public int PulseDivider3 { get; set; }

        public double Current3 { get; set; }
        public double Gain3 { get; set; }
        public double GainHs3 { get; set; }

        /// <summary>
        /// Gets or sets the TriggerSource 1...4.
        /// </summary>
        public int TriggerSource3 { get; set; }

        /// <summary>
        /// Gets or sets the flag indicating whether Image Height is adjusted around the Z-calibarated Zero Position.
        /// </summary>
        public bool HeightZeroAdjustEnabled3 { get; set; }

        /// <summary>
        /// Gets or sets the pointcloud ASC file additional attributes.
        /// 0: x, y, z coordinates
        /// 1: coordinates + intensity in float format.
        /// 2: coordinates + grayscale value in RGB format. 
        /// 3: coordinates, + intensity + grayscale. 
        /// </summary>
        public int PointCloudAscFormat3 { get; set; }

        /// <summary>
        /// Gets or sets the FIR length for camera.
        /// </summary>
        public int FirLength3 { get; set; }

        /// <summary>
        /// Gets or sets the Average FIR length for camera.
        /// </summary>
        public int AverFirLength3 { get; set; }

        /// <summary>
        /// Gets or sets the detection filter length for camera.
        /// </summary>
        public int DetectionFilter3 { get; set; }

        /// <summary>
        /// Gets or sets the average intensity length for camera.
        /// </summary>
        public int AverageIntensityFilter3 { get; set; }

        /// <summary>
        /// Gets or sets the intensity threshold for camera.
        /// </summary>
        public int Threshold3 { get; set; }

        /// <summary>
        /// Gets or sets the maximum point count per profile for camera.
        /// </summary>
        public int MaxPointCount3 { get; set; }

        /// <summary>
        /// Gets or sets the hdr.
        /// </summary>
        public bool HdrEnabled3 { get; set; }

        /// <summary>
        /// Gets or sets the VLow2.
        /// </summary>
        public int VLow23 { get; set; } = 114;

        /// <summary>
        /// Gets or sets the VLow3.
        /// </summary>
        public int VLow33 { get; set; } = 116;

        /// <summary>
        /// Gets or sets the Kp1Pos.
        /// </summary>
        public int Kp1Pos3 { get; set; } = 10;

        /// <summary>
        /// Gets or sets the Kp2Pos.
        /// </summary>
        public int Kp2Pos3 { get; set; } = 25;

        public int ExpectedCameraCount3 { get; set; }

        private string _cameraIdString3;
        private Dictionary<string, string> _cameraIds3 = new Dictionary<string, string>();

        /// <summary>
        /// Gets or sets the camera id string containing MAC and logical names.
        /// </summary>
        public string CameraIdString3
        {
            get { return _cameraIdString; }
            set { _cameraIdString = value; }
        }

        /// <summary>
        /// Gets or sets the save rate used in ASC file saving. 
        /// </summary>
        [JsonIgnore]
        public int SaveRate3 { get; set; }

        /// <summary>
        /// Gets or sets the camera id string format.
        /// </summary>
        [JsonIgnore]
        public Dictionary<string, string> CameraIds3
        {
            get
            {
                _cameraIds.Clear();
                if (string.IsNullOrEmpty(_cameraIdString))
                    return _cameraIds;

                string[] items = _cameraIdString.TrimEnd(';').Split(';');
                foreach (string item in items)
                {
                    string[] keyValue = item.Split('=');
                    _cameraIds.Add(keyValue[0], keyValue[1]);
                }
                return _cameraIds;
            }
            set
            {
                _cameraIds = value;
                _cameraIdString = string.Join(";", _cameraIds.Select(x => x.Key + "=" + x.Value));
            }
        }

        /// <summary>
        /// Sensor width
        /// </summary>
        [JsonIgnore]
        public int SensorWidth3 { get; set; }

        /// <summary>
        /// Sensor x offset in pixels
        /// </summary>
        [JsonIgnore]
        public int XOffset3 { get; set; }

        /// <summary>
        /// Sensor type identifier offset in pixels
        /// </summary>
        [JsonIgnore]
        public int SensorType3 { get; set; }

        /// <summary>
        /// Gets the flag indicating whether the Z calibration data is set or not.
        /// </summary>
        [JsonIgnore]
        public bool IsZCalibrationDataSet3
        {
            get { return !string.IsNullOrEmpty(ZCalibrationFile); }
        }

        /// <summary>
        /// Gets the flag indicating whether the X calibration data is set or not.
        /// </summary>
        [JsonIgnore]
        public bool IsXCalibrationDataSet3
        {
            get { return !string.IsNullOrEmpty(XCalibrationFile); }
        }

        /// <summary>
        /// Gets the min. x of the optical profile in [mm].
        /// </summary>
        [JsonIgnore]
        public double OpticalProfileMinX3 { get; set; }

        /// <summary>
        /// Gets the min. x of the optical profile in [mm].
        /// </summary>
        [JsonIgnore]
        public double OpticalProfileMaxX3 { get; set; }

        //-----------------------------------------------------------------------






        /// <summary>
        /// Singleton instance.
        /// </summary>
        private static volatile ApplicationSettings _instance;

        /// <summary>
        /// Protects from concurrent object instantiation.
        /// </summary>
        private static readonly object InstanceLock = new object();

        /// <summary>
        /// Assings default settings.
        /// </summary>
        private ApplicationSettings()
        {
            LedPulseWidth = Defines.DefaultPulseWidth;
            MaxLedPulseWidth = Defines.DefaultMaxPulseWidth;
            Freq = Defines.DefaultTriggerFrequency;
            IpAddress = Defines.DefaultIpAddress;
            ZCalibrationFile = Defines.DefaultZCalibrationFile;
            XCalibrationFile = Defines.DefaultXCalibrationFile;
            UiWindowHeight = Defines.DefaultUiWindowSize;
            IsAgcEnabled = Defines.DefaultAgcState;
            AgcTargetIntensity = Defines.DefaultAgcTargetIntensity;
            PulseDivider = Defines.DefaultPulseDivider;
            Current = Defines.DefaultCurrent;
            Gain = Defines.DefaultGain;
            GainHs = Defines.DefaultGainHs;
            TriggerSource = Defines.DefaultTriggerSource;
            HeightZeroAdjustEnabled = Defines.HeightZeroAdjustState;
            PointCloudAscFormat = Defines.DefaultPointCloudAscFormat;
            FirLength = Defines.DefaultFirLength;
            AverFirLength = Defines.DefaultAverFirLength;
            DetectionFilter = Defines.DefaultDetectionFilter;
            AverageIntensityFilter = Defines.DefaultAverageIntensityFilter;
            Threshold = Defines.DefaultThreshold;
	        SensorWidth = Defines.DefaultSensorWidth;
	        SaveRate = Defines.DefaultSaveRate;
	        MaxPointCount = Defines.DefaultMaxPointCount;
            ExpectedCameraCount = Defines.DefaultExpectedCameraCount;

            //---------------------------------------------------------
            LedPulseWidth2 = Defines.DefaultPulseWidth;
            MaxLedPulseWidth2 = Defines.DefaultMaxPulseWidth;
            Freq2 = Defines.DefaultTriggerFrequency;
            IpAddress2 = Defines.DefaultIpAddress;
            ZCalibrationFile2 = Defines.DefaultZCalibrationFile;
            XCalibrationFile2 = Defines.DefaultXCalibrationFile;
            UiWindowHeight2 = Defines.DefaultUiWindowSize;
            IsAgcEnabled2 = Defines.DefaultAgcState;
            AgcTargetIntensity2 = Defines.DefaultAgcTargetIntensity;
            PulseDivider2 = Defines.DefaultPulseDivider;
            Current2 = Defines.DefaultCurrent;
            Gain2 = Defines.DefaultGain;
            GainHs2 = Defines.DefaultGainHs;
            TriggerSource2 = Defines.DefaultTriggerSource;
            HeightZeroAdjustEnabled2 = Defines.HeightZeroAdjustState;
            PointCloudAscFormat2 = Defines.DefaultPointCloudAscFormat;
            FirLength2 = Defines.DefaultFirLength;
            AverFirLength2 = Defines.DefaultAverFirLength;
            DetectionFilter2 = Defines.DefaultDetectionFilter;
            AverageIntensityFilter2 = Defines.DefaultAverageIntensityFilter;
            Threshold2 = Defines.DefaultThreshold;
            SensorWidth2 = Defines.DefaultSensorWidth;
            SaveRate2 = Defines.DefaultSaveRate;
            MaxPointCount2 = Defines.DefaultMaxPointCount;
            ExpectedCameraCount2 = Defines.DefaultExpectedCameraCount;

            //---------------------------------------------------------
            LedPulseWidth3 = Defines.DefaultPulseWidth;
            MaxLedPulseWidth3 = Defines.DefaultMaxPulseWidth;
            Freq3 = Defines.DefaultTriggerFrequency;
            IpAddress3 = Defines.DefaultIpAddress;
            ZCalibrationFile3 = Defines.DefaultZCalibrationFile;
            XCalibrationFile3 = Defines.DefaultXCalibrationFile;
            UiWindowHeight3 = Defines.DefaultUiWindowSize;
            IsAgcEnabled3 = Defines.DefaultAgcState;
            AgcTargetIntensity3 = Defines.DefaultAgcTargetIntensity;
            PulseDivider3 = Defines.DefaultPulseDivider;
            Current3 = Defines.DefaultCurrent;
            Gain3 = Defines.DefaultGain;
            GainHs3 = Defines.DefaultGainHs;
            TriggerSource3 = Defines.DefaultTriggerSource;
            HeightZeroAdjustEnabled3 = Defines.HeightZeroAdjustState;
            PointCloudAscFormat3 = Defines.DefaultPointCloudAscFormat;
            FirLength3 = Defines.DefaultFirLength;
            AverFirLength3 = Defines.DefaultAverFirLength;
            DetectionFilter3 = Defines.DefaultDetectionFilter;
            AverageIntensityFilter3 = Defines.DefaultAverageIntensityFilter;
            Threshold3 = Defines.DefaultThreshold;
            SensorWidth3 = Defines.DefaultSensorWidth;
            SaveRate3 = Defines.DefaultSaveRate;
            MaxPointCount3 = Defines.DefaultMaxPointCount;
            ExpectedCameraCount3 = Defines.DefaultExpectedCameraCount;


        }

        /// <summary>
        /// Calculates min. and max. calibrated values from the calibration data given.
        /// </summary>
        /// <param name="calibrationFile">Full path to the calibration data.</param>
        /// <param name="varMin">Calibration polynomial min. parameter value.</param>
        /// <param name="varMax">Calibration polynomial max. parameter value.</param>
        /// <param name="calibMin">Min. calibrated value found.</param>
        /// <param name="calibMax">Max. calibrated value found.</param>
        /// <param name="avgGain">Average gain value among polynomials.</param>
        private void GetCalibrationProperties(string calibrationFile, int varMin, int varMax, out double calibMin, out double calibMax, out double avgGain)
        {
            calibMin = double.MaxValue;
            calibMax = double.MinValue;
            avgGain = 0.0;
            string[] lines;
            try
            {
                lines = File.ReadAllLines(calibrationFile);
            }
            catch
            {
                return;
            }
         
            List<double> gain = new List<double>();

            foreach (string line in lines)
            {
                if (line.Contains(";"))
                {
                    List<double> coeffs = line.Split(';').Skip(1).Select(s => double.Parse(s, CultureInfo.InvariantCulture)).ToList();

                    gain.Add(coeffs[1]);
				    double minCandidate = Math.Min(Horner(coeffs, varMin), Horner(coeffs, varMax));
                    double maxCandidate = Math.Max(Horner(coeffs, varMin), Horner(coeffs, varMax));

                    calibMin = minCandidate < calibMin ? minCandidate : calibMin;
                    calibMax = maxCandidate > calibMax ? maxCandidate : calibMax;
                }
            }

            avgGain = gain.Average();
        }


        private void GetPointsFromFile(string PointCloudFile, int varMin, int varMax, out double calibMin, out double calibMax, out double avgGain)
        {
            calibMin = double.MaxValue;
            calibMax = double.MinValue;
            avgGain = 0.0;
            string[] lines;
            int LineCount=0;
            try
            {
                lines = File.ReadAllLines(PointCloudFile);
            }
            catch
            {
                return;
            }
            float[] z = new float[LineCount];
            float[] Intensity = new float[LineCount]; ;
            //float[,] a = new float[LineCount,3];
            for(int i = 0; i<LineCount;i++ )
            {
                z[i] = Convert.ToSingle(lines[i].Split(' ').Skip(2));
                Intensity[i] = Convert.ToSingle(lines[i].Split(' ').Skip(3));

            }
         
        }

        /// <summary>
        /// Horner polynomial evaluation routine at given x.
        /// </summary>
        /// <param name="coeffs">Polynomial coefficients: 0 degree, 1st degree, ..., nth degree.</param>
        /// <param name="x">Parameter value.</param>
        /// <returns>Value of the polynomial at x.</returns>
        private double Horner(List<double> coeffs, double x)
        {
            double s = 0.0f;

            for (int i = coeffs.Count-1; i >= 0; i--)
            {
                s = s * x + coeffs[i];
            }

	        return s;
        }

        /// <summary>
        /// Saves settings to file.
        /// </summary>
        public void SaveToFile()
        {
            string json = JsonConvert.SerializeObject(this, Formatting.Indented);

            File.WriteAllText(Defines.ApplicationSettingsFile, json);
        }

        /// <summary>
        /// Loads settings from file.
        /// </summary>
        /// <returns>New MainViewSettings object initialized from the read settings.</returns>
        public static ApplicationSettings LoadFromFile()
        {
            if (_instance == null)
            {
                lock (InstanceLock)
                {
                    if (_instance == null)
                    {
                        if (!File.Exists(Defines.ApplicationSettingsFile))
                        {
                            _instance = new ApplicationSettings();
                        }
                        else
                        {
                            string json = File.ReadAllText(Defines.ApplicationSettingsFile);

                            _instance = JsonConvert.DeserializeObject<ApplicationSettings>(json);
                        }
                    }
                }
            }

            return _instance;
        }
    }
}
